#include <time.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/unistd.h>

void api_function() {
    // 创建读写锁
    pthread_rwlock_t rwlock;

    // 初始化读写锁
    pthread_rwlock_init(&rwlock, NULL);

    // 加读锁
    pthread_rwlock_rdlock(&rwlock);

    // 尝试加读锁
    pthread_rwlock_tryrdlock(&rwlock);

    // 解锁
    pthread_rwlock_unlock(&rwlock);

    // 加写锁
    pthread_rwlock_wrlock(&rwlock);

    // 尝试写读锁
    pthread_rwlock_trywrlock(&rwlock);

    // 解锁
    pthread_rwlock_unlock(&rwlock);

    // 销毁读写锁
    pthread_rwlock_destroy(&rwlock);
};

int count1 = 0;

void *callback1(void *arg) {
    for (int i = 0; i < 100; ++i) {
        int number = count1;
        number++;
        usleep(1000 * 20 * (*(int *) arg));
        count1 = number;
        // printf("count1 = %d\n", count1);
        usleep(1000 * 10 * (*(int *) arg));
    }
}

void *callback2(void *arg) {
    for (int i = 0; i < 200; ++i) {
        int number = count1;
        usleep(1000 * 20 * (*(int *) arg));
        // printf("count1 = %d\n", count1);
        usleep(1000 * 10 * (*(int *) arg));
    }
}

void thread_unsafe() {
    struct timeval start, end;
    gettimeofday(&start, NULL);

    pthread_t pid1, pid2, pid3, pid4, pid5;
    int value1 = 1;
    int value2 = 2;
    int value3 = 3;

    pthread_create(&pid1, NULL, callback1, &value3);
    pthread_create(&pid2, NULL, callback1, &value2);
    pthread_create(&pid3, NULL, callback2, &value1);
    pthread_create(&pid4, NULL, callback2, &value2);
    pthread_create(&pid5, NULL, callback2, &value2);

    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);
    pthread_join(pid3, NULL);
    pthread_join(pid4, NULL);
    pthread_join(pid5, NULL);

    printf("count1 = %d\n", count1);

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("use time: %d\n", use_time);
}

int count2 = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *callback3(void *arg) {
    for (int i = 0; i < 100; ++i) {
        pthread_mutex_lock(&mutex);
        int number = count2;
        number++;
        usleep(1000 * 20 * (*(int *) arg));
        count2 = number;
        // printf("count2 = %d\n", count2);
        pthread_mutex_unlock(&mutex);
    }
}

void *callback4(void *arg) {
    for (int i = 0; i < 200; ++i) {
        pthread_mutex_lock(&mutex);
        int number = count2;
        usleep(1000 * 20 * (*(int *) arg));
        // printf("count2 = %d\n", count2);
        pthread_mutex_unlock(&mutex);
    }
}

void thread_safe_by_mutex() {
    struct timeval start, end;
    gettimeofday(&start, NULL);

    pthread_t pid1, pid2, pid3, pid4, pid5;
    int value1 = 1;
    int value2 = 2;
    int value3 = 3;

    pthread_create(&pid1, NULL, callback3, &value3);
    pthread_create(&pid2, NULL, callback3, &value2);
    pthread_create(&pid3, NULL, callback4, &value1);
    pthread_create(&pid4, NULL, callback4, &value2);
    pthread_create(&pid5, NULL, callback4, &value2);

    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);
    pthread_join(pid3, NULL);
    pthread_join(pid4, NULL);
    pthread_join(pid5, NULL);

    printf("count2 = %d\n", count2);

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("use time: %d\n", use_time);
}

int count3 = 0;

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

void *callback5(void *arg) {
    for (int i = 0; i < 100; ++i) {
        pthread_rwlock_wrlock(&rwlock);
        int number = count3;
        number++;
        usleep(1000 * 20 * (*(int *) arg));
        count3 = number;
        // printf("count3 = %d\n", count3);
        pthread_rwlock_unlock(&rwlock);
    }
}

void *callback6(void *arg) {
    for (int i = 0; i < 100; ++i) {
        pthread_rwlock_rdlock(&rwlock);
        int number = count3;
        usleep(1000 * 20 * (*(int *) arg));
        count3 = number;
        // printf("count3 = %d\n", count3);
        pthread_rwlock_unlock(&rwlock);
    }
}

// 在读多写少的情况下, 读写锁就比简单的互斥锁好
void thread_safe_by_rwlock() {
    struct timeval start, end;
    gettimeofday(&start, NULL);

    pthread_t pid1, pid2, pid3, pid4, pid5;
    int value1 = 1;
    int value2 = 2;
    int value3 = 3;

    pthread_create(&pid1, NULL, callback5, &value3);
    pthread_create(&pid2, NULL, callback5, &value2);
    pthread_create(&pid3, NULL, callback6, &value1);
    pthread_create(&pid4, NULL, callback6, &value2);
    pthread_create(&pid5, NULL, callback6, &value2);

    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);
    pthread_join(pid3, NULL);
    pthread_join(pid4, NULL);
    pthread_join(pid5, NULL);

    printf("count3 = %d\n", count2);

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("use time: %d\n", use_time);
}


int main() {
    thread_unsafe();
    thread_safe_by_mutex();
    thread_safe_by_rwlock();
}